package org.microsleep.sqlite;

import java.util.Collection;

import org.microsleep.ORMUtil;
import org.microsleep.PersistentClass;
import org.microsleep.Property;
import org.microsleep.Type;
import org.microsleep.Util;
import org.microsleep.Util.F;

import android.database.Cursor;
import android.database.sqlite.SQLiteStatement;

public class SQLiteUtil extends ORMUtil {
	private static final Type TYPE_TEXT = new SQLiteType<String>() {

		public String getSQLDefinition() {
			return "TEXT";
		}

		public void bindInStatement(SQLiteStatement statement, int index,
				Property property, String value) {
			statement.bindString(index, value);
		}

		public String getJavaValue(Cursor db, int index) {
			return db.getString(index);
		}

	};

	private static final Type TYPE_INTEGER = new IntegerType<Integer>() {

		public Integer getJavaValue(Cursor db, int index) {
			return Integer.valueOf(db.getInt(index));
		}

		public void bindInStatement(SQLiteStatement statement, int index,
				Property property, Integer value) {
			statement.bindLong(index, value.longValue());
		}
	};

	{
		registerDefaultTypes();
	}

	private void registerDefaultTypes() {
		setTypeFor(Integer.TYPE, TYPE_INTEGER);
		setTypeFor(Integer.class, TYPE_INTEGER);
		setTypeFor(String.class, TYPE_TEXT);
	}

	@Override
	public void setTypeFor(Class<?> javaClass, Type type) {
		Util.notNull(javaClass);
		Util.notNull(type);
		Util.isTrue((type instanceof SQLiteType<?>)
				|| type instanceof PersistentClass, "Unsupported type: " + type);
		super.setTypeFor(javaClass, type);
	}

	public String getCreateTableStatement(PersistentClass mapping) {
		StringBuilder builder = new StringBuilder();
		builder.append("CREATE TABLE ");
		builder.append(mapping.getTableName()).append(" (");
		builder.append(Util.concat(
				Util.map(mapping.getProperties(), new F<Property, String>() {
					public String f(Property in) {
						StringBuilder b = new StringBuilder(in.getName());
						b.append(' ');
						Type type = in.getType();
						if (type instanceof PersistentClass) {
							PersistentClass pClass = (PersistentClass) type;
							type = pClass.getIdentifier().getType();
						}
						SQLiteType<?> sqLiteType = (SQLiteType<?>) type;
						b.append(sqLiteType.getSQLDefinition());

						return b.toString();
					}

				}), ", "));
		builder.append(" )");
		return builder.toString();
	}

	public String getStoreStatement(PersistentClass mapping,
			Collection<Property> properties) {
		StringBuilder builder = new StringBuilder();
		builder.append("INSERT OR REPLACE INTO ")
				.append(mapping.getTableName()).append(" (");
		builder.append(Util.concat(
				Util.map(mapping.getProperties(), new F<Property, String>() {
					public String f(Property in) {
						return in.getName();

					}
				}), ", "));
		builder.append(") VALUES (");
		builder.append(Util.concat(
				Util.map(mapping.getProperties(), new F<Property, String>() {
					public String f(Property in) {
						return "?";
					}
				}), ", "));

		builder.append(")");
		return builder.toString();
	}

	@Override
	public String getLoadStatement(PersistentClass pClass,
			Collection<Property> properties) {
		StringBuilder builder = new StringBuilder();
		builder.append("SELECT ");
		builder.append(Util.concat(
				Util.map(pClass.getProperties(), new F<Property, String>() {
					public String f(Property in) {
						return in.getName();

					}
				}), ", "));
		builder.append(" FROM ").append(pClass.getTableName())
				.append(" where ").append(pClass.getIdentifier().getName())
				.append(" = ?");
		return builder.toString();
	}
}
